//== SAGITTARIUS ============================================================================

//== BEGINNING OF CODE ===============================================================

#include "sagittarius/core/SagittariusCore.h"

//SAGITTARIUS headers:
#include "sagittarius/parallel/mutex.h"
#include "sagittarius/parallel/atomics.h"
//#define __USE_GNU
#include "sagittarius/platform/syscall.h"
#include <linux/futex.h>
#include <sys/time.h>
#include <sys/syscall.h>
#include <limits.h>

#ifndef NULL
#   define NULL 0
#endif

void init_mutex(mutex_t *f) {
    *f = 0;
}

void lock_mutex(mutex_t *f) {
    mutex_t ff;
    for(;;) {
        ff = *f;
        //try uncontended case
        if(ff == 0)
            if(sg_cas32(f, 0, 1))
                return; //success: uncontended
        //set state to contended if it wasn't already
        if(ff == 1)
            if(sg_cas32(f, 1, 2))
                syscall(SYS_futex, f, FUTEX_WAIT, 2, NULL/*timeout*/);
        if(ff == 2)
            syscall(SYS_futex, f, FUTEX_WAIT, 2, NULL/*timeout*/);
    }
    //lock is now held
}

void unlock_mutex(mutex_t *f) {
    mutex_t ff;
    for(;;) {
        ff = *f;
        //try uncontended case
        if(ff == 1)
            if(sg_cas32(f, 1, 0))
                return;
        //if there are waiters, then wake someone up
        if(ff == 2)
            if(sg_cas32(f, 2, 0))
                syscall(SYS_futex, f, FUTEX_WAKE, 1 /*INT_MAX*/); //this futex is exclusive, so only wake one
    }
}
